﻿using System;
using System.IO;
using System.Reflection;
using System.Globalization;
using System.Collections.Generic;
using System.Security.Principal;

using SBPweb.Modules.Modularity;
using SBPweb.Modules.Smartparts;
using SBPweb.Modules.Logging;
using SBPweb.Modules.Communication;

using SBPweb.Services.Base;

namespace SBPweb.Services.Host
{

    public class ModuleHost : IModuleHost
    {

        #region Private fields

        private ILogManager pLogManager;
        private ModuleLoader pModuleLoader;

        private Dictionary<string, ModuleDescriptor> pMDs;
        private Dictionary<string, ModuleInfo> pMIs;

        #endregion

        #region Constructor logic

        public ModuleHost()
        {
            pLogManager = new LogManager();
            pLogManager.Initialize();

            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
            AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(CurrentDomain_AssemblyLoad);

            string resolvePath = SBPweb.Common.Configuration.ConfigurationHandler.PhysicalRootDirectory + Properties.Settings.Default.PathOfModules;
            AppDomain.CurrentDomain.AppendPrivatePath(resolvePath);

            pModuleLoader = new ModuleLoader(resolvePath, Properties.Settings.Default.PatternOfModules, Properties.Settings.Default.ApplicationTitle, "SBPweb tech", LogManager);
            pModuleLoader.ModuleLoading += new EventHandler<ModuleDescriptorEventArgs>(pModuleLoader_ModuleLoading);
            pModuleLoader.ModuleLoaded += new EventHandler<ModuleEventArgs>(pModuleLoader_ModuleLoaded);

            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

            pModuleLoader.Initialize(this, "None");
        }

        #endregion

        #region Property accessors

        public ModuleHostType HostType
        {
            get
            {
                return ModuleHostType.WebForms;
            }
        }

        public ILayoutProvider LayoutProvider
        {
            get { throw new NotImplementedException(); }
        }

        public ILogManager LogManager
        {
            get
            {
                return pLogManager;
            }
        }

        public ModuleLoader ModuleLoader
        {
            get
            {
                return pModuleLoader;
            }
        }

        public IPrincipal SecurityPrincipal
        {
            get { throw new NotImplementedException(); }
        }

        public CultureInfo[] SupportedCultures
        {
            get
            {
                return new CultureInfo[]{ new CultureInfo("en-US") };
            }
        }

        public IPersistable ParentPersistable
        {
            get { throw new NotImplementedException(); }
        }

        public string PersistencyKey
        {
            get { throw new NotImplementedException(); }
        }

        public Dictionary<string, ModuleDescriptor> ModuleDescriptors
        {
            get
            {
                lock (this)
                {
                    if (pMDs == null)
                    {
                        pMDs = Global.ApplicationHost.GetServiceDescriptors();
                    }
                    return pMDs;
                }
            }
        }

        public Dictionary<string, ModuleInfo> ModuleInfos
        {
            get
            {
                lock (this)
                {
                    if (pMIs == null)
                    {
                        pMIs = new Dictionary<string, ModuleInfo>();
                    }
                    return pMIs;
                }
            }
        }

        public MenuBase Menu
        {
            get { throw new NotImplementedException(); }
        }

        public MessageQueueBase Messages
        {
            get { throw new NotImplementedException(); }
        }

        public SmartpartListBase Smartparts
        {
            get { throw new NotImplementedException(); }
        }

        public MenuBase StatusBar
        {
            get { throw new NotImplementedException(); }
        }

        #endregion

        #region Events

        public event EventHandler OnApplicationClosing;

        #endregion

        #region Methods

        public void SetCulture(System.Globalization.CultureInfo ci)
        {
            throw new NotImplementedException();
        }

        public Dictionary<string, ModuleDescriptor> GetServiceDescriptors()
        {
            if (pModuleLoader == null)
            {
                return new Dictionary<string, ModuleDescriptor>();
            }
            ModulesConfiguration mc = pModuleLoader.LoadModulesConfiguration();
            return mc.ModuleDescriptors;
            /*
            ModuleDescriptor[] ret = (ModuleDescriptor[])Array.CreateInstance(typeof(ModuleDescriptor), mc.ModuleDescriptors.Count);
            mc.ModuleDescriptors.Values.CopyTo(ret, 0);
            return ret;
            */
        }

        #endregion

        #region Event handlers

        private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            pLogManager.WriteWarning(sender, string.Format("Assembly load failed: {0}", args.Name), "General");

            return null;
        }

        private void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
        {
            pLogManager.WriteInfo(sender, string.Format("Assembly loaded: {0}", args.LoadedAssembly.FullName), "General");
        }

        private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            pLogManager.WriteCritical(sender, e.ExceptionObject as Exception, SeverityLevel.Critical.ToString());
        }

        private void pModuleLoader_ModuleLoading(object sender, ModuleDescriptorEventArgs e)
        {
            pLogManager.WriteInfo(sender, string.Format("Loading of {0} module has been started.", e.Descriptor.ModuleTypeName), "ModuleLoader");
        }

        private void pModuleLoader_ModuleLoaded(object sender, ModuleEventArgs e)
        {
            pLogManager.WriteInfo(sender, string.Format("{0} (v{1}) module has been loaded.", e.Module, e.Module.Version), "ModuleLoader");
        }

        #endregion

    }

}